using System;
using System.Collections.Generic;

namespace Is
{
    public sealed class Is<TTarget> : IsBase<Is<TTarget>, TTarget>
    {
        internal Is(TTarget target, bool negate) : base(target, negate) { }

        public Is<TTarget> Not
        {
            get
            {
                negate = !negate;
                return this;
            }
        }

        public Has<TTarget> Has()
        {
            return new Has<TTarget>(((IIs<TTarget>)this).Target, ((IIs<TTarget>)this).Negate);
        }

        public bool Equal(TTarget expected)
        {
            return ((IIs<TTarget>)this).Apply(
                t => Core.Is.Equal(t, expected),
                t => Core.Is.NotEqual(t, expected));
        }

        public bool Equal(TTarget expected, IEqualityComparer<TTarget> comparer)
        {
            return ((IIs<TTarget>)this).Apply(
                t => Core.Is.Equal(t, expected, comparer),
                t => Core.Is.NotEqual(t, expected, comparer));
        }

        public bool Null()
        {
            return ((IIs<TTarget>)this).Apply(
                t => Core.Is.Null(t),
                t => Core.Is.NotNull(t));
        }

        public bool SameAs(TTarget expected)
        {
            return ((IIs<TTarget>)this).Apply(
                t => Core.Is.Same(t, expected),
                t => Core.Is.NotSame(t, expected));
        }

        public bool OfType<TExpectedType>()
        {
            return OfType(typeof(TExpectedType));
        }

        public bool OfType(Type expectedType)
        {
            return ((IIs<TTarget>)this).Apply(
                t => Core.Is.IsType(t, expectedType),
                t => !Core.Is.IsType(t, expectedType));
        }

        public bool AssignableFrom<TExpected>()
        {
            return AssignableFrom(typeof(TExpected));
        }

        public bool AssignableFrom(Type expectedType)
        {
            return ((IIs<TTarget>)this).Apply(
                t => Core.Is.AssignableFrom(t, expectedType),
                t => !Core.Is.AssignableFrom(t, expectedType));
        }

        public bool InRange(TTarget low, TTarget high)
        {
            return ((IIs<TTarget>)this).Apply(
                t => Core.Is.InRange(t, low, high),
                t => Core.Is.NotInRange(t, low, high));
        }

        public bool InRange(TTarget low, TTarget high, IComparer<TTarget> comparer)
        {
            return ((IIs<TTarget>)this).Apply(
                t => Core.Is.InRange(t, low, high, comparer),
                t => Core.Is.NotInRange(t, low, high, comparer));
        }

        public bool GreaterThan(TTarget value)
        {
            return ((IIs<TTarget>)this).Apply(
                t => Core.Is.GreaterThan(t, value),
                t => Core.Is.LessThanOrEqual(t, value));
        }

        public bool GreaterThan(TTarget value, IComparer<TTarget> comparer)
        {
            return ((IIs<TTarget>)this).Apply(
                t => Core.Is.GreaterThan(t, value, comparer),
                t => Core.Is.LessThanOrEqual(t, value, comparer));
        }

        public bool GreaterThanOrEqualTo(TTarget value)
        {
            return ((IIs<TTarget>)this).Apply(
                t => Core.Is.GreaterThanOrEqual(t, value),
                t => Core.Is.LessThan(t, value));
        }

        public bool GreaterThanOrEqualTo(TTarget value, IComparer<TTarget> comparer)
        {
            return ((IIs<TTarget>)this).Apply(
                t => Core.Is.GreaterThanOrEqual(t, value, comparer),
                t => Core.Is.LessThan(t, value, comparer));
        }

        public bool LessThan(TTarget value)
        {
            return ((IIs<TTarget>)this).Apply(
                t => Core.Is.LessThan(t, value),
                t => Core.Is.GreaterThanOrEqual(t, value));
        }

        public bool LessThan(TTarget value, IComparer<TTarget> comparer)
        {
            return ((IIs<TTarget>)this).Apply(
                t => Core.Is.LessThan(t, value, comparer),
                t => Core.Is.GreaterThanOrEqual(t, value, comparer));
        }

        public bool LessThanOrEqualTo(TTarget value)
        {
            return ((IIs<TTarget>)this).Apply(
                t => Core.Is.LessThanOrEqual(t, value),
                t => Core.Is.GreaterThan(t, value));
        }

        public bool LessThanOrEqualTo(TTarget value, IComparer<TTarget> comparer)
        {
            return ((IIs<TTarget>)this).Apply(
                t => Core.Is.LessThanOrEqual(t, value, comparer),
                t => Core.Is.GreaterThan(t, value, comparer));
        }

        public bool ConvertableTo<T>()
        {
            return ((IIs<TTarget>)this).Apply(
                Core.Is.ConvertableTo<TTarget, T>,
                t => !Core.Is.ConvertableTo<TTarget, T>(t));
        }
    }
}